/*
 * Copyright 2002-2006 the original author or authors. Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License. You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 * either express or implied. See the License for the specific language governing permissions and limitations under the
 * License.
 */
package pikes.xml;

import pikes.util.Assert;
import pikes.util.Util;

/**
 * Entity which represents an XML document. When creating it, at least the root tag has to be specified.<br>
 * <p>
 * Example1:<br>
 * <code>
 * XMLDocument doc = new XMLDocument(new XMLTag("name"));<br>
 * Writer writer = new OutputStreamWriter(System.out);<br>
 * doc.print(writer);<br>
 * writer.flush();<br>
 * </code> will print <br>
 * <code>&lt;?xml version=&quot;1.0&quot;?&gt;&lt;name/&gt;</code> <br>
 * to the standard output.
 * @author Peter Bona
 */
public class XMLDocument extends PrintableXMLMarkup {

	private XMLTag root = null;

	private DocType docType = null;

	private CharSequence encoding = null;

	/**
	 * Creates an XML document.
	 * @param root the root XML tag
	 */
	public XMLDocument(final XMLTag root) {
		Assert.notNull(root);
		this.root = root;
	}

	/**
	 * Creates an XML document.
	 * @param root the root XML tag
	 * @param docType the doc type for the root XML tag
	 */
	public XMLDocument(final XMLTag root, final DocType docType) {
		this(root);
		this.docType = docType;
	}

	/**
	 * Creates an XML document.
	 * @param root the root XML tag
	 * @param encoding encoding of the XML document
	 */
	public XMLDocument(final XMLTag root, final CharSequence encoding) {
		this(root);
		this.encoding = encoding;
	}

	/**
	 * Creates an XML document.
	 * @param root the root XML tag
	 * @param docType the doc type for the root XML tag
	 * @param encoding decoding of the XML document
	 */
	public XMLDocument(final XMLTag root, final DocType docType, final CharSequence encoding) {
		this(root, docType);
		this.encoding = encoding;
	}

	/**
	 * Visits this XML document. The order of method calls is the following:
	 * <ol>
	 * <li>{@link XMLVisitor#xmlDeclaration(CharSequence)} or if <code>decoding</code> is not null
	 * {@link XMLVisitor#xmlDeclaration(CharSequence,CharSequence)} </li>
	 * <li>{@link XMLVisitor#publicDocType(CharSequence,CharSequence,CharSequence)}, if there is a public doc type
	 * defined in the XMLDocument</li>
	 * <li>{@link XMLTag#visit(XMLVisitor)} for the root XML tag</li>
	 * </ol>
	 * @param xmlVisitor the visitor
	 * @throws XMLVisitingException when anything goes wrong when visiting XML declaration, the doc type and the root
	 * tag
	 */
	public final void visit(XMLVisitor xmlVisitor) throws XMLVisitingException {
		if (Util.hasText(encoding)) {
			xmlVisitor.xmlDeclaration("1.0", encoding);
		}
		else {
			xmlVisitor.xmlDeclaration("1.0");
		}

		if (docType != null) {
			docType.visit(xmlVisitor);
		}
		root.visit(xmlVisitor);
	}

	/**
	 * Retrieves the encoding of the XML document
	 * @return Encoding
	 */
	public final CharSequence getEncoding() {
		return encoding;
	}

	/**
	 * Sets the encoding
	 * @param encoding as character sequence
	 */
	public final void setEncoding(CharSequence encoding) {
		this.encoding = encoding;
	}

}
